# -*- coding: utf-8 -*-
# @Time    : 2024/6/26 11:29
# @Author  : yujiahao
# @File    : 14_pandas_sample_analysis.py
# @description:pandas中的随机抽样和重采样


"""
在 Pandas 中，sample() 函数用于对数据集进行随机抽样。以下是 sample() 函数的语法格式及参数说明：

    DataFrame.sample(n=None, frac=None, replace=False, weights=None, random_state=None, axis=None)

参数说明如下：

    参数名称    参数说明
    n          表示要抽取的行数。
    frac       表示抽取的比例，比如 frac=0.5，代表抽取总体数据的50%。
    replace    布尔值参数，表示是否以有放回抽样的方式进行选择，默认为 False，取出数据后不再放回。
    weights    可选参数，代表每个样本的权重值，参数值是字符串或者数组。
    random_state 可选参数，控制随机状态，默认为 None，表示随机数据不会重复；若为 1 表示会取得重复数据。
    axis       表示在哪个方向上抽取数据(axis=1 表示列/axis=0 表示行)。

该函数返回与数据集类型相同的新对象，相当于 numpy.random.choice()。

"""
import numpy as np
import pandas as pd


# todo 1、Pandas sample随机抽样
def pandas_sample():
    info = pd.DataFrame({'data1': [2, 6, 8, 0], 'data2': [2, 5, 0, 8], 'data3': [12, 2, 1, 8]},
                        index=['John', 'Parker', 'Smith', 'William'])

    print('原始数据：\n', info)

    print('''\n-----------------------------------☆☆☆分割线☆☆☆----------------------------------------\n''')

    # 默认随机选择两行
    print(info.sample(n=2))

    print('''\n-----------------------------------☆☆☆分割线☆☆☆----------------------------------------\n''')

    # 随机选择两列
    print(info.sample(n=2, axis=1))

    print('''\n-----------------------------------☆☆☆分割线☆☆☆----------------------------------------\n''')

    # 随机抽取3个数据
    print(info['data1'].sample(n=3))

    print('''\n-----------------------------------☆☆☆分割线☆☆☆----------------------------------------\n''')

    # 总体的50%
    '''假设你有一个包含 100 行数据的 DataFrame，frac=0.5 表示你希望随机抽取 50% 的数据，即 50 行。如果 DataFrame 只有 10 行数据，frac=0.5 则会随机抽取 5 行。
    
    frac 参数是一个浮点数，表示要抽取的样本占原始数据的比例。它的值应在 0 到 1 之间。例如：

    frac=0.1 表示抽取 10% 的数据。
    frac=0.25 表示抽取 25% 的数据。
    frac=0.75 表示抽取 75% 的数据。
    '''
    print(info.sample(frac=0.5, replace=True))

    print('''\n-----------------------------------☆☆☆分割线☆☆☆----------------------------------------\n''')

    # data3序列为权重值，并且允许重复数据出现，相当于设置了一个固定种子，重复运行代码结果不变
    print(info.sample(n=2, weights='data3', random_state=1))


# todo 2、Pandas resample数据重采样

"""
    数据重采样是将时间序列从一个频率转换至另一个频率的过程，它主要有两种实现方式，分别是降采样和升采样。
    
        降采样：将高频率(间隔短)数据转换为低频率(间隔长)。
        
        升采样：将低频率数据转换为高频率。
    
    Pandas 提供了 resample() 函数来实现数据的重采样。
"""


def pandas_resample():
    # 降采样

    # 通过 resample() 函数完成数据的降采样，比如按天计数的频率转换为按月计数。
    rng = pd.date_range('1/1/2021', periods=100, freq='D')
    ts = pd.Series(np.random.randn(len(rng)), index=rng)
    # 降采样后并聚合
    ts.resample('ME').mean()
    print('''\n-----------------------------------☆☆☆分割线☆☆☆----------------------------------------\n''')
    # 如果您只想看到月份，那么您可以设置kind = period如下所示：
    ts.resample('ME', kind='period').mean()
    print('''\n-----------------------------------☆☆☆分割线☆☆☆----------------------------------------\n''')

    # 升采样

    # 升采样是将低频率（时间间隔）转换为高频率，示例如下：

    # 生成一份时间序列数据
    rng = pd.date_range('1/1/2021', periods=20, freq='3D')
    ts = pd.Series(np.random.randn(len(rng)), index=rng)

    print('''\n-----------------------------------☆☆☆分割线☆☆☆----------------------------------------\n''')

    print(ts.head())

    # 使用asfreq()在原数据基础上实现频率转换
    '''
        其他常见的方法
            mean(): 计算重新采样后的平均值。
            sum(): 计算重新采样后的总和。
            ohlc(): 计算重新采样后的开盘价、最高价、最低价和收盘价。
            ffill(): 前向填充缺失值。
            bfill(): 后向填充缺失值。
    
    例如，使用 ffill() 方法来填充缺失值：        
    ts_resampled_ffill = ts.resample('D').ffill()
    print("前向填充后的数据:")
    print(ts_resampled_ffill.head())
    '''
    print(ts.resample('D').asfreq().head())

    print('''\n-----------------------------------☆☆☆分割线☆☆☆----------------------------------------\n''')

    # 频率转换
    # asfreq() 方法不仅能够实现频率转换，还可以保留原频率对应的数值，同时它也可以单独使用，示例如下：
    index = pd.date_range('1/1/2021', periods=6, freq='min')
    series = pd.Series([0.0, None, 2.0, 3.0, 4.0, 5.0], index=index)
    df = pd.DataFrame({'s': series})
    print(df.asfreq("45s"))

    print('''\n-----------------------------------☆☆☆分割线☆☆☆----------------------------------------\n''')

    # 插值处理

    '''
    从上述示例不难看出，升采样的结果会产生缺失值，那么就需要对缺失值进行处理，一般有以下几种处理方式：
    
        方法	                    说明
        ------------------------------------------------
        pad/ffill	            用前一个非缺失值去填充缺失值。
        backfill/bfill	        用后一个非缺失值去填充缺失值。
        interpolater('linear')	线性插值方法。
        fillna(value)	        指定一个值去替换缺失值。
    
    '''

    # 使用插值方法处理 NaN 值
    # 创建时间序列数据
    rng = pd.date_range('1/1/2021', periods=20, freq='3D')
    ts = pd.Series(np.random.randn(len(rng)), index=rng)

    print(ts.resample('D').asfreq().head())

    print('''\n-----------------------------------☆☆☆分割线☆☆☆----------------------------------------\n''')

    # 使用ffill处理缺失值
    ts.resample('D').asfreq().ffill().head()


def main():
    # pandas_sample()
    pandas_resample()


if __name__ == '__main__':
    main()
